package controller.adder;

import errors.CoordinatesNotAcceptableException;
import errors.KeyNotFoundException;
import errors.StratumNotFoundException;
import event.numberevent.NumberEvent;
import event.numberevent.StateNumber;
import gui.Display;

import java.awt.event.KeyEvent;
import java.awt.event.MouseEvent;

import javax.swing.JScrollPane;
import javax.swing.JViewport;

import advance.GameMap;

import mapelements.foreground.MapObject;

import controller.ObjectAdderInformationContainer;

/**indica come deve essere aggiunto un MapObject
 * all'interno della mappa. La procedura in questione è:
 * <ul>
 *  <li>alla pressione del tasto sinistro (o doppio click) il mapObject selezionato viene inserito nella mappa</li>
 *  <li>alla pressione del tasto destro il mapObject precedentemente inserito viene eliminato dalla mappa</li>
 *  <li>ogni altro pulsante non produce risultati</li>
 *</ul>
 * 
 * Il MapObjectAdder può aggiungere anche più uguali istanze di MapObject in una sola passata (per esempio se si vuole inserire una serie
 * di alberi): in questo caso, al momento dell'inserzione, verrà postposto al {@link #baseKey}, un numero in modo che le chiavi
 * dei mapObject siano tutte diverse tra di loro. Tale possibilità è tuttavia possibile se e solo se {@link #speedInsertEnable} è TRUE: per far
 * si che tale variabile sia TRUE è necessario che il MapObject da inserire estenda correttamente il metodo <tt>clone()</tt> di Object (non è tuttavia encessario
 * che estenda l'interfaccia Cloneable). Di default {@link #speedInsertEnable} è FALSE, per motivi precauzionali.
 * <p>il MapObject consta di 3 variabili di base:
 * <ol>
 *  <li>{@link #baseKey} indica la stringa che assumerà il ruolo di chiave nella mappa. in caso verranno inseriti più mapObject la 
 *   <tt>baseKey</tt> verrà seguita da un numero in modo da rendere univoca la chiave stessa (tranne 0)</li>
 *  <li>{@link #currentstratum} indica il numero dello strato in cui aggiungere ogni MapObject</li>
 *  <li>{@link #mapObjectnumber} indica il numero con cui si dovrà concatenare {@link #baseKey} quando si dovrà aggiungere il prossimo
 *  foreground.</li>
 * </ol>
 * 
 * è importante far notare che il metodo di aggiunta di MapObjectAdder è di tipo Unsecure: se la chiave da usare per inserire il nuovo foreground
 * nella mappa indirizza già un precedente foreground, il vecchio foreground <strong>verrà sovrascritto senza alcun avviso per l'utente</strong>.
 * 
 * @author Koldar
 * @version 1.2
 */
public class MapObjectAdder extends ObjectAdderInformationContainer<MapObject>{

	
	//TODO fare in modo che in futuro l'editor avvisi che si sta sovrascrivendo un vecchio foreground con una certa chiave!!!
	/**indica lo strato in cui i mapObject vanno inseriti*/
	private int currentstratum;
	/**indica la chiave con cui inserire il MapObject nella mappa. In caso di aggiunte multiple verranno postposti dei numeri a tale chiave*/
	private String baseKey;
	/**indica il numero da postporre alla {@link #baseKey}. In caso il mapObjectnumber sia 0 tale numero non deve essere concatenato alla chiave*/
	private int mapObjectnumber;
	/**se TRUE indica che è possibile, una volta scelta la classe da inserire, cliccare più volte sulla mappa in punti diversi per inserire gli stessi MapObject. di default è FALSE*/
	private boolean speedInsertEnable;
	
	public MapObjectAdder(Display whereToAdd, MapObject _objectToAdd,GameMap map,int currentstratum,String basekey) {
		super(whereToAdd, _objectToAdd,map);
		this.currentstratum=currentstratum;
		this.baseKey=basekey;
		this.mapObjectnumber=0;
		this.speedInsertEnable=false;
	}

	@Override
	public void doubleClick(MouseEvent arg0) throws StratumNotFoundException {
		this.leftClick(arg0);
	}

	@Override
	public void leftClick(MouseEvent arg0) throws StratumNotFoundException {
		MapObject copy;
		try {
			copy = this.objectToAdd.clone();
			this.speedInsertEnable=true;
		} catch (CloneNotSupportedException error) {
			//la modalità inserimento rapido non è disponibile!
			copy=this.objectToAdd;
			this.speedInsertEnable=false;
		}
		int mapx=arg0.getX()/(this.map.getMapresolution());
		int mapy=arg0.getY()/(this.map.getMapresolution());
		copy.setX(mapx);
		copy.setY(mapy);
		try{
			System.out.println(this.baseKey+(this.mapObjectnumber==0?"":Integer.toString(mapObjectnumber)));
			this.map.addUnsecureForeground(this.currentstratum,this.baseKey+(this.mapObjectnumber==0?"":Integer.toString(mapObjectnumber)),copy);
		} catch (CoordinatesNotAcceptableException error){//non devo fare nulla
		}
		if (this.speedInsertEnable){
			this.mapObjectnumber++;
		}
	}
	@Override
	public void rightClick(MouseEvent arg0) {
		if (this.mapObjectnumber==0){//non è stato aggiunto ancora alcun foreground
			return;
		}
		this.mapObjectnumber--; //il mapObjectNumber indica il prossimo da inserire... ma noi vogliamo togliere un foreground quindi bisogna prima togliere 1 dal mapObjectNumber per trovare un numero che identifica un foreground!
		try{
			this.map.removeForeground(baseKey+(this.mapObjectnumber==0?"":Integer.toString(mapObjectnumber)));
		} catch (KeyNotFoundException error){
			//in caso la chiave non sia stata trovata, non deve succedere nulla ^^
		}
	}
	@Override
	public void unknownClick(MouseEvent arg0) {
	}

	@Override
	public void enterTyped(KeyEvent arg0) {
	}

	@Override
	public void escTyped(KeyEvent arg0) {
	}

	@Override
	public void unkwnownTyped(KeyEvent arg0) {
	}

}
